package com.jalarbee.core.money;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.Locale;

import javax.persistence.Basic;
import javax.persistence.Transient;

import com.jalarbee.core.util.MoneyOperator;
import com.jalarbee.core.util.exception.MoneyChangeException;
import com.jalarbee.core.util.exception.UnknownChangeRateException;
import java.text.NumberFormat;

public class MonetaryAmount implements Serializable {

    private static final long serialVersionUID = 1L;
    public static final Currency DEFAUTCURRENCY = Currency.getInstance(Locale.US);
    @Transient	// WHY IS IT SO??
    private Currency currency;
    @Basic
    private BigDecimal amount;

    public MonetaryAmount() {
        this.amount = new BigDecimal(0);
        this.currency = DEFAUTCURRENCY;
    }

    public MonetaryAmount(Currency currency, BigDecimal amount) {
        super();
        this.currency = currency;
        this.amount = amount;
    }

    public MonetaryAmount(BigDecimal amount) {
        super();
        this.amount = amount;
        this.currency = DEFAUTCURRENCY;
    }

    public Currency getCurrency() {
        return currency;
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        if (this.currency == DEFAUTCURRENCY) {
            this.amount = amount;
        } else {
            try {
                this.amount = MoneyOperator.getAmount(currency, amount);
            } catch (MoneyChangeException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (UnknownChangeRateException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }

    }

    public MonetaryAmount times(double factor) {
        this.amount = this.amount.multiply(BigDecimal.valueOf(factor));
        return this;
    }

    public MonetaryAmount times(int factor) {
        this.amount = this.amount.multiply(BigDecimal.valueOf(factor));
        return this;
    }

    public MonetaryAmount add(MonetaryAmount price) {
        this.amount = this.amount.add(price.getAmount());
        return this;
    }

    public MonetaryAmount substract(MonetaryAmount price) {
        this.amount = this.amount.subtract(price.getAmount());
        return this;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof MonetaryAmount) {
            MonetaryAmount ma = (MonetaryAmount) obj;
            if (obj == this) {
                return true;
            }
            if (this.getCurrency().getSymbol().equals(ma.getCurrency().getSymbol()) && ma.getAmount().equals(this.amount)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        return currency.hashCode() + amount.hashCode() * 17;
    }

    @Override
    public String toString() {
        NumberFormat decimalFormat = NumberFormat.getInstance(Locale.US);
        decimalFormat.setCurrency(currency);
        decimalFormat.setMinimumFractionDigits(2);
        return decimalFormat.format(amount);
    }
}
